﻿namespace SMSOverEmail
{
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Net.Mail;
    using System.Text.RegularExpressions;

    public class SMSOverEmail
    {
        private string _smtpUserName;
        private string _smtpPassword;
        private string _phoneNumber;
        private int _port;
        private string _host;
        private bool _enableSsl = false;
        private MailAddress _from;
        private string _subject;
        private string _body;
        private Carrier? _recipientCarrier; //nullable so we can check for null value
        private Regex phoneRegex = new Regex(@"^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$");
        private Carriers carriers = new Carriers();
        private SmtpClient client = new SmtpClient();

        /// <summary>
        /// The Username to use for the SMTP Client.
        /// </summary>
        public string SMTPUserName
        {
            get { return _smtpUserName; }
            set
            {
                _smtpUserName = value;
            }
        }

        /// <summary>
        /// The Password to use for the SMTP Client.
        /// </summary>
        public string SMTPPassword
        {
            get { return _smtpPassword; }
            set
            {
                _smtpPassword = value;
            }
        }

        /// <summary>
        /// The Port to use for the SMTP Client.
        /// </summary>
        public int Port
        {
            get { return _port; }
            set { _port = value; }
        }

        /// <summary>
        /// The Host to use for the SMTP Client.
        /// </summary>
        public string Host
        {
            get { return _host; }
            set { _host = value; }
        }

        /// <summary>
        /// True to Enable Ssl for the SMTP Client.  False otherwise.
        /// </summary>
        public bool EnableSsl
        {
            get { return _enableSsl; }
            set { _enableSsl = value; }
        }

        /// <summary>
        /// The sender of the message.
        /// </summary>
        public MailAddress From
        {
            get { return _from; }
            set { _from = value; }
        }

        /// <summary>
        /// The message subject line.
        /// </summary>
        public string Subject
        {
            get { return _subject; }
            set { _subject = value; }
        }

        /// <summary>
        /// The message to send.
        /// </summary>
        public string Message
        {
            get { return _body; }
            set { _body = value; }
        }

        /// <summary>
        /// The Phone number to send to.
        /// </summary>
        public string PhoneNumber
        {
            get { return _phoneNumber; }
            set { _phoneNumber = formatPhoneNumber(value); }
        }

        /// <summary>
        /// The Phone number's carrier.
        /// </summary>
        public Carrier? RecipientCarrier
        {
            get { return _recipientCarrier; }
            set { _recipientCarrier = value; }
        }

        /// <summary>
        /// A structure to use for creating a text message object.
        /// </summary>
        public struct TextMessage
        {
            public string PhoneNumber;
            public Carrier RecipientCarrier;
            public string Message;
            public string Subject;
        }

        /// <summary>
        /// Formats a phone number to just a 10 digit number.
        /// </summary>
        /// <param name="value">The phone number to format.</param>
        /// <returns>A 10 digit phone number.</returns>
        private string formatPhoneNumber(string value)
        {
            return phoneRegex.Replace(value, "$1$2$3");
        }

        /// <summary>
        /// A list of carrier names and their associated carrier enum.
        /// </summary>
        public Dictionary<Carrier?, string> CarrierNames
        {
            get
            {
                return this.carriers.CarrierNames;
            }
        }

        /// <summary>
        /// Send a text message.
        /// </summary>
        public void SendTextMessage()
        {
            checkForExceptions();
            string address = carriers.Addresses[this.RecipientCarrier].Replace("#", this.PhoneNumber);

            using (var mail = new MailMessage())
            {
                mail.To.Add(new MailAddress(address));
                mail.From = this.From;
                mail.Subject = this.Subject;
                mail.Body = this.Message;

                client.Credentials = new NetworkCredential(this.SMTPUserName, this.SMTPPassword);
                client.Port = this.Port;
                client.Host = this.Host;
                client.EnableSsl = this.EnableSsl;

                client.Send(mail);
            }
        }

        /// <summary>
        /// Send a text message.
        /// </summary>
        /// <param name="message">The message to send.</param>
        public void SendTextMessage(string message)
        {
            this.Message = message;
            this.SendTextMessage();
        }

        /// <summary>
        /// Send a text message.
        /// </summary>
        /// <param name="message">The message to send.</param>
        /// <param name="subject">The subject line.</param>
        public void SendTextMessage(string message, string subject)
        {
            this.Message = message;
            this.Subject = subject;
            this.SendTextMessage();
        }

        /// <summary>
        /// Send a text message.
        /// </summary>
        /// <param name="phoneNumber">The phone number to send the message to.</param>
        /// <param name="carrier">The carrier the phone number belongs to.</param>
        /// <param name="message">The message to send.</param>
        public void SendTextMessage(string phoneNumber, Carrier carrier, string message)
        {
            this.PhoneNumber = phoneNumber;
            this.Message = message;
            this.RecipientCarrier = carrier;
            this.SendTextMessage();
        }

        /// <summary>
        /// Send a text message.
        /// </summary>
        /// <param name="textMessage">Th TextMessage to send.</param>
        public void SendTextMessage(TextMessage textMessage)
        {
            this.SendTextMessage(textMessage.PhoneNumber, textMessage.RecipientCarrier, textMessage.Message, textMessage.Subject);
        }

        /// <summary>
        /// Send a text message.
        /// </summary>
        /// <param name="phoneNumber">The phone number to send the message to.</param>
        /// <param name="carrier">The carrier the phone number belongs to.</param>
        /// <param name="message">The message to send.</param>
        /// <param name="subject">The subject line.</param>
        public void SendTextMessage(string phoneNumber, Carrier carrier, string message, string subject)
        {
            this.Subject = subject;
            this.SendTextMessage(phoneNumber, carrier, message);
        }

        /// <summary>
        /// Send a text message.
        /// </summary>
        /// <param name="phoneNumber">The phone number to send the message to.</param>
        /// <param name="carrier">The carrier the phone number belongs to.</param>
        /// <param name="message">The message to send.</param>
        /// <param name="subject">The subject line.</param>
        /// <param name="from">The MailAddress of who the message is from.</param>
        public void SendTextMessage(string phoneNumber, Carrier carrier, string message, string subject, MailAddress from)
        {
            this.From = from;
            this.SendTextMessage(phoneNumber, carrier, message, subject);
        }

        /// <summary>
        /// Send a text message.
        /// </summary>
        /// <param name="numbers">A dictionary of phone numbers to send to.  The dictionary is in the form of Dictionary<PhoneNumber, Carrier>.</param>
        /// <param name="message">The message to send to the phone numbers.</param>
        /// <param name="subject">The subject line.</param>
        /// <param name="from">The MailAddress of who the message is from.</param>
        public void SendTextMessage(Dictionary<string, Carrier> numbers, string message, string subject, MailAddress from)
        {
            this.Message = message;
            this.Subject = subject;
            this.From = from;

            foreach(KeyValuePair<string, Carrier> number in numbers)
            {
                this.PhoneNumber = number.Key;
                this.RecipientCarrier = number.Value;
                this.SendTextMessage();
            }
        }

        /// <summary>
        /// Send a text message.
        /// </summary>
        /// <param name="messages">A list of TextMessages to send.</param>
        public void SendTextMessage(List<TextMessage> messages)
        {
            foreach(TextMessage message in messages)
            {
                SendTextMessage(message);
            }
        }

        /// <summary>
        /// Throws any exceptions that there may be.
        /// </summary>
        private void checkForExceptions()
        {
            if (string.IsNullOrEmpty(this.Host))
            {
                throw new Exception("SMTP Host Required.");
            }

            if (string.IsNullOrEmpty(this.Port.ToString()))
            {
                throw new Exception("SMTP Port Required.");
            }

            if (string.IsNullOrEmpty(this.SMTPUserName) || string.IsNullOrEmpty(this.SMTPPassword))
            {
                throw new Exception("SMTP Email and Password Are Required.");
            }

            if (this.From == null)
            {
                throw new Exception("From Address Is Required.");
            }

            if (string.IsNullOrEmpty(this.PhoneNumber))
            {
                throw new Exception("Phone Number Is Required.");
            }

            if (this.RecipientCarrier == null)
            {
                throw new Exception("Chosen Carrier Is Required.");
            }

            if (string.IsNullOrEmpty(this.Message))
            {
                throw new Exception("Message Is Required.");
            }
        }
    }
}
